﻿/// <reference path="../Core.ts" />

module Supernova {

    export class Galaxy {

        public mode: GameMode;

        public diameter: number = 0;

        /// <field name="age" type="Number">The galaxy's age, in seconds.</field>
        public age: number = 0;

        public lastTime: number = 0;
        public speedMultiplier: number = 1;
        public science: number = 0;
        public scienceThreshold: number = SCIENCE_FIRST_COST;
        public gold: number = 0;
        public home: { systems: Array<StarSystem>; system: StarSystem; body: Body } = { systems: [], system: null, body: null };
        public currentView: IZoomPoint = { x: 0, y: 0, zoom: MIN_ZOOM_LEVEL };
        public targetView: IZoomPoint = { x: 0, y: 0, zoom: STARTING_ZOOM_LEVEL };

        public profile: GeneratorProfile = null;
        public starSystems: Array<StarSystem> = [];
        public ships: Array<Ship> = [];
        public missiles: Array<Missile> = [];
        public artillery: Array<Artillery> = [];
        public wrecks: Array<Wreck> = [];
        public effects: Effects = null;
        public ai: AIHandler = null;

        //#warning Make player-specific so that AI can have it's own ie artillery stats
        public research = {
            artillery: {
                ship: { enabled: false, wait: ARTILLERY_DEFAULT_WAIT_SHIP, pods: 0 },
                planetary: { enabled: false, wait: ARTILLERY_DEFAULT_WAIT_PLANETARY, radius: config.artillery.initialRadius, strength: 1, ignoreOrbitals: false }
            },
            facilities: { comms: false, scanner: false, mining: false, orbital: false },
            actions: { repair: false, explore: false, draft: false, terraformGasGiants: false },
            passive: { reclaim: false, efficientTerraforming: false, efficientScanners: false, refining: false }
        };

        public population: number = 0;
        public enemyPlanetCount: number = 0;
        public enemyPopulation: number = 0;
        public state: GalaxyState = GalaxyState.setup;

        public calculated: {
            humanSystems: Array<StarSystem>; humanBodies: Array<Body>; humanShips: Array<Ship>; enemySystems: Array<StarSystem>; enemyBodies: Array<Body>; enemyShips: Array<Ship>
        } = {
            humanSystems: [], humanBodies: [], humanShips: [], enemySystems: [], enemyBodies: [], enemyShips: []
        };

        constructor(mode: GameMode, profile: GeneratorProfile) {
            this.mode = mode;
            this.profile = profile;
        }

        public unlockVictory() {
            this.state = GalaxyState.victoryUnlocked;
        }

        public spendGold(amount: number): boolean {
            if (this.gold >= amount) {
                this.gold -= amount;
                return true;
            }
            return false;
        }

        public addScience(amount: number) {
            if (this.science < this.scienceThreshold && this.science + amount > this.scienceThreshold && this.mode != GameMode.replay) {
                Sounds.play(Sounds.items.researchAvailable);
            }
            this.science += amount;
        }

        public spendScience() {
            this.science -= this.scienceThreshold;
            this.scienceThreshold += SCIENCE_ADDITIONAL_COST_PER_USE;
            Sounds.play(Sounds.items.blip);
        }

        public isInScanningRange(x: number, y: number): boolean {

            // Human bodies can have scanners that make ships visible
            for (var i = 0; i < this.calculated.humanBodies.length; i++) {
                var body = this.calculated.humanBodies[i];
                var scannerRange = this.research.passive.efficientScanners ? config.scanning.range.withFacility * 1.25 : config.scanning.range.withFacility;
                var range = body.facilities.scanner ? scannerRange : config.scanning.range.noFacility;
                if (body.population > 0 && insideCircle(body.x, body.y, x, y, range)) {
                    return true;
                }
            }

            // Human ships have scanners that make other ships visible
            for (var i = 0; i < this.calculated.humanShips.length; i++) {
                var scanner = this.calculated.humanShips[i];
                if (insideCircle(scanner.currentLocation.x, scanner.currentLocation.y, x, y, scanner.scanning)) {
                    return true;
                }
            }

            // Nothing has made a ship visible
            return false;
        }

        public discoverAll() {
            for (var i = 0; i < this.starSystems.length; i++) {
                var system = this.starSystems[i];
                system.discovered = true;
            }
            for (var i = 0; i < this.wrecks.length; i++) {
                var wreck = this.wrecks[i];
                wreck.visible = true;
            }
        }

        public stopAction() {
            var shipsToStop = findSelectedShips(function (s) { return s.calculated.canStop; });
            for (var shipKey in shipsToStop) {
                var ship = shipsToStop[shipKey];
                if (ship.owner == OwnerType.human) {
                    ship.stopAction();
                }
            }
        }

        public coloniseAction(queue: boolean) {
            var shipsToColonise = findSelectedShips(function (s) { return s.calculated.canColonise || queue; });
            for (var shipKey in shipsToColonise) {
                var ship = shipsToColonise[shipKey];
                if (ship.owner == OwnerType.human) {
                    if (queue) {
                        ship.orders.push(ShipOrder.create(ShipOrderType.colonise));
                    } else {
                        ship.coloniseAction(ship.currentLocation.body);
                    }
                }
            }
        }

        public terraformAction(queue: boolean) {
            var shipsToTerraform = findSelectedShips(function (s) { return s.calculated.canTerraform || queue; });
            for (var shipKey in shipsToTerraform) {
                var ship = shipsToTerraform[shipKey];
                if (ship.owner == OwnerType.human) {
                    if (queue) {
                        ship.orders.push(ShipOrder.create(ShipOrderType.terraform));
                    } else {
                        ship.terraformAction(ship.currentLocation.body);
                    }
                }
            }
        }

        public bombardAction(queue: boolean) {
            var shipsToBombard = findSelectedShips(function (s) { return s.calculated.canBombard || queue; });
            for (var shipKey in shipsToBombard) {
                var ship = shipsToBombard[shipKey];
                if (ship.owner == OwnerType.human) {
                    if (queue) {
                        ship.orders.push(ShipOrder.create(ShipOrderType.bombard));
                    } else {
                        ship.bombardAction(ship.currentLocation.body);
                    }
                }                
            }
        }

        public exploreAction(queue: boolean) {
            for (var shipKey in selected.ships) {
                var ship = selected.ships[shipKey];
                if (ship.owner == OwnerType.human) {
                    if (queue) {
                        ship.orders.push(ShipOrder.create(ShipOrderType.explore));
                    } else {
                        ship.exploreAction();
                    }
                }
            }
        }

        public repairAction(queue: boolean) {
            var shipsToRepair = findSelectedShips(function (s) { return s.calculated.canRepair || queue; });
            for (var shipKey in shipsToRepair) {
                var ship = shipsToRepair[shipKey];
                if (ship.owner == OwnerType.human) {
                    if (queue) {
                        ship.orders.push(ShipOrder.create(ShipOrderType.repair));
                    } else {
                        ship.repairAction();
                    }
                }
            }
        }

        public disbandAction(queue: boolean) {
            var shipsToDisband = findSelectedShips(function (s) { return s.calculated.canDisband || queue; });
            for (var shipKey in shipsToDisband) {
                var ship = shipsToDisband[shipKey];
                if (ship.owner == OwnerType.human) {
                    if (queue) {
                        ship.orders.push(ShipOrder.create(ShipOrderType.disband));
                    } else {
                        ship.disbandAction();
                    }
                }
            }
        }

    }

}